# These targets make Kokoro complain that the Ninja version is too low.
#add_custom_target(all_xc7_iosettings_generate)
#add_custom_target(all_xc7_iosettings_bin)
#add_custom_target(all_xc7_iosettings_bit_v)
#add_custom_target(all_xc7_iosettings_vivado_diff_fasm)

function(xc7_iosettings_design)
  # ~~~
  # XC7_IOSETTINGS_DESIGN (
  #   BOARD <board>
  #   MODE <mode>
  #   IOSTANDARD <iostandard>
  #   [VREF <vref>]
  #   [DRIVES <drive value list>]
  #   [SLEWS <slew setting list>]
  #   [TERMS <IN_TERM setting list]
  #   )
  # ~~~
  #
  # Generates a design that tests support for a particular IOSTANDARD in the
  # given mode of operation. The MODE can be: "input", "output" or "inout" and
  # for differential IO: "diff_input", "diff_output" and "diff_inout".
  #
  # There is always a single IOSTANDARD per design, but there may be more
  # combinations of DRIVE, SLEW and IN_TERM settings. These lists are given
  # in DRIVES, SLEWS and TERMS parameters.
  #
  # The VREF parameter specifies an internal vref to be set on the IO bank
  # If omitted then no internal vref is set.
  #
  # The BOARD parameter specifies the pinout variant. Please refer to the
  # generate.py script for the list of legal values.
  #
  # IMPORTANT: Please also note that designs generated by this function are
  # not meant to run on an actual hardware!
  #

    # Parse arguments
    set(OPTION_ARGS
        DISABLE_DIFF_TEST
    )
    set(ONE_VALUE_ARGS
        BOARD
        MODE
        IOSTANDARD
        VREF
    )
    set(MULTI_VALUE_ARGS
        DRIVES
        SLEWS
        TERMS
    )

    cmake_parse_arguments(
        XC7_IOSETTINGS_DESIGN
        "${OPTION_ARGS}"
        "${ONE_VALUE_ARGS}"
        "${MULTI_VALUE_ARGS}"
        ${ARGN}
    )

    # Get args
    set(BOARD ${XC7_IOSETTINGS_DESIGN_BOARD})
    set(MODE  ${XC7_IOSETTINGS_DESIGN_MODE})
    set(IOSTANDARD ${XC7_IOSETTINGS_DESIGN_IOSTANDARD})
    set(VREF  ${XC7_IOSETTINGS_DESIGN_VREF})

    separate_arguments(DRIVE_LIST UNIX_COMMAND ${XC7_IOSETTINGS_DESIGN_DRIVES})
    separate_arguments(SLEW_LIST  UNIX_COMMAND ${XC7_IOSETTINGS_DESIGN_SLEWS})
    separate_arguments(TERM_LIST  UNIX_COMMAND ${XC7_IOSETTINGS_DESIGN_TERMS})

    # Disable Vivado diff fasm test
    if(${XC7_IOSETTINGS_DESIGN_DISABLE_DIFF_TEST})
        set(VIVADO_ARGS DISABLE_DIFF_TEST)
    else()
        set(VIVADO_ARGS "")
    endif()

    # Generate options
    set(GEN_OPTS)

    if(DRIVE_LIST)
        set(GEN_OPTS ${GEN_OPTS} "--drive" ${DRIVE_LIST})
    endif()

    if(SLEW_LIST)
        set(GEN_OPTS ${GEN_OPTS} "--slew" ${SLEW_LIST})
    endif()

    if(TERM_LIST)
        set(GEN_OPTS ${GEN_OPTS} "--in_term" ${TERM_LIST})
    endif()

    if(NOT ${VREF} STREQUAL "")
        set(GEN_OPTS ${GEN_OPTS} "--vref" ${VREF})
        set(DESIGN ${MODE}_${BOARD}_${IOSTANDARD}_${VREF}V)
    else()
        set(DESIGN ${MODE}_${BOARD}_${IOSTANDARD})
    endif()

    # Generate the design
    set(VERILOG_FILE ${DESIGN}.v)
    set(PCF_FILE ${DESIGN}.pcf)
    set(XDC_FILE ${DESIGN}.xdc)

    add_file_target(FILE ${VERILOG_FILE} GENERATED)
    add_file_target(FILE ${PCF_FILE} GENERATED)
    add_file_target(FILE ${XDC_FILE} GENERATED)

    add_custom_command(
        OUTPUT ${VERILOG_FILE} ${PCF_FILE} ${XDC_FILE}
        COMMAND ${PYTHON3} ${CMAKE_CURRENT_SOURCE_DIR}/generate.py
            --board ${BOARD}
            --mode ${MODE}
            -o ${DESIGN}
            --iostandard ${IOSTANDARD}
            ${GEN_OPTS}
        DEPENDS ${PYTHON3} ${PYTHON3_TARGET} generate.py
        )

    # Add target
    add_fpga_target(
        NAME ${DESIGN}
        BOARD ${BOARD}
        INPUT_IO_FILE ${PCF_FILE}
        INPUT_XDC_FILE ${XDC_FILE}
        SOURCES ${VERILOG_FILE}
        EXPLICIT_ADD_FILE_TARGET
        # Enable non-dedicated routes for clocks in fasm2bels until the problem
        # of BUFG placement is solved. Those routes are not of concern for this
        # test.
        BIT_TO_V_EXTRA_ARGS --allow-non-dedicated-clk-routes
        )

    add_vivado_target(
        NAME ${DESIGN}_vivado
        PARENT_NAME ${DESIGN}
        CLOCK_PINS clk
        CLOCK_PERIODS 10.0
        XDC ${XDC_FILE}
        ${VIVADO_ARGS}
        )

#    get_file_target(TARGET_V   ${DESIGN}.v)
#    get_file_target(TARGET_PCF ${DESIGN}.pcf)
#    get_file_target(TARGET_XDC ${DESIGN}.xdc)
#    add_dependencies(all_xc7_iosettings_generate ${TARGET_V} ${TARGET_PCF} ${TARGET_XDC})

#    add_dependencies(all_xc7_iosettings_bin ${DESIGN}_bin)
#    add_dependencies(all_xc7_iosettings_bit_v ${DESIGN}_bit_v)
#    add_dependencies(all_xc7_iosettings_vivado_diff_fasm ${DESIGN}_vivado_diff_fasm)

endfunction()

# =============================================================================

set(BOARD "arty-full")

# Single ended
foreach(MODE input output inout)

    # Input termination is only relevan for input
    if(MODE STREQUAL "input")
        set(TERMS "NONE UNTUNED_SPLIT_40 UNTUNED_SPLIT_50 UNTUNED_SPLIT_60")
    else()
        set(TERMS "NONE")
    endif()

    # Drive current set #1
    foreach(IOSTANDARD LVCMOS15 LVCMOS25 LVCMOS33)
        xc7_iosettings_design(
            MODE ${MODE}
            BOARD ${BOARD}
            IOSTANDARD ${IOSTANDARD}
            DRIVES "4 8 12 16"
            SLEWS "SLOW FAST"
            TERMS "NONE"
        )
    endforeach()

    # Drive current set #2
    foreach(IOSTANDARD LVTTL) # Disabled LVCMOS18 due to #1263 (PUDC_B pin issues)
        xc7_iosettings_design(
            MODE ${MODE}
            BOARD ${BOARD}
            IOSTANDARD ${IOSTANDARD}
            DRIVES "4 8 12 16 24"
            SLEWS "SLOW FAST"
            TERMS "NONE"
        )
    endforeach()

    # Drive current set #3
    xc7_iosettings_design(
        MODE ${MODE}
        BOARD ${BOARD}
        IOSTANDARD LVCMOS12
        DRIVES "4 8 12"
        SLEWS "SLOW FAST"
        TERMS "NONE"
    )

    # Fixed drive current
    foreach(IOSTANDARD SSTL135 SSTL15)

        # VREF is only relevant for input/inout
        if(NOT MODE STREQUAL "output")
            foreach(VREF 0.600 0.675 0.750 0.900)
                xc7_iosettings_design(
                    MODE ${MODE}
                    BOARD ${BOARD}
                    IOSTANDARD ${IOSTANDARD}
                    SLEWS "SLOW FAST"
                    TERMS ${TERMS}
                    VREF ${VREF}
                )
            endforeach()

        # Output mode, no VREF setting
        else()
            xc7_iosettings_design(
                MODE ${MODE}
                BOARD ${BOARD}
                IOSTANDARD ${IOSTANDARD}
                SLEWS "SLOW FAST"
                TERMS ${TERMS}
            )
        endif()
    endforeach()

endforeach()

# Differential
foreach(MODE diff_output diff_inout)
    foreach(IOSTANDARD DIFF_SSTL135 DIFF_SSTL15)
        xc7_iosettings_design(
            MODE ${MODE}
            BOARD ${BOARD}
            IOSTANDARD ${IOSTANDARD}
            SLEWS "SLOW FAST"
            TERMS "NONE"
        )
    endforeach()
endforeach()

